"""
递归函数：一个函数在自己的函数体中调用自己，这个就叫做递归
但是：递归函数一定要有一个停下来的条件，不能一直调用下去
递归必须满足两个条件
有终止的条件（出口）
每一次调用都更接近于终止的条件
"""


# 计算从1 - n  的和

# def sun_to_n(n):   # 定义了一个函数，接受的参数是 n
#     if n ==1:    # 设置的出口，防止无限的递归
#         return 1    #当n减小到 1 的时候，不继续调用1 而是返回1
#     return n+sun_to_n(n-1)       #函数调用自身 n-1 直到达到出口的条件   n =1
# result = sun_to_n(3)   # 传入了一个参数   n = 4
# print(result)

"""
3
3-1 =2
2-1 =1
"""

# 当你调用了一个函数 你要告诉python 你目前到了哪一步



"""
sun_to_n(4)   sun_to_n(3)     3+?  记住   放了一个盘子
。。。。。
 sun_to_n(1) 满足了n ==1 直接返回1   最上面的盘子完成
 
 拿出2+？     2+1 =3    3+？  3+3 = 6


sum_to_n(3)  最先调用的，但是在最底下
sunm_to_n(2)
sun_to_n(1)  最后调用的，但是在最上面  （先完成的部分）

 sun_to_n(1)  返回1
  sun_to_n(2)  返回2 +1 =3
   sun_to_n(3)  返回3+3 =6

"""





# 如果没有出口会怎么样

# def bad_recursion(n):
#     return n + bad_recursion(n - 1)  # 没有 if n == 1 的判断！
#
# result = bad_recursion(3)   # 传入了一个参数   n = 3
# print(result)


#没有一个终止的条件，导致函数无限的调用自己  栈就会越来越高，直到python说：RecursionError: maximum recursion depth exceeded
#



"""

匿名函数：

python使用lambda 来创建
所谓的匿名函数，就是不使用def这种的标准的形式来定义函数
lambda的主体是一个变大时，而不是一个代码块，仅仅能在lambda表达式中封装有限的逻辑
只能写一个表达式不能写多行语句
自动的 reture的表达式结果
通常用于临时，简单的函数场景
lambda  不是更快，二是更简洁


"""





#
# sum  = lambda num1,num2,num3:num1+num2+num3
# print(sum(10,20,30))
#




# def add(x,y):
#     return  x+y
#
# add_lambda = lambda x,y:x+y
# print(add(2,3))
# print(add_lambda(2,3))

#匿名函数精髓就是没有名字

# print((lambda x:x*2)(5))


#作为参数传递
 #python的匿名函数 + 内置函数一起使用  （高阶函数）

# num = [1,2,3,4]
# squared = list(map(lambda x:x**2,num))   #  x:x**2 接收x 返回x的平方
# """
# map是高阶函数：主要作用是遍历元素，并且对元素调用func   在这里是lambda
# """
# print(squared)


#字典的排序
   #创建一个字典 里面有三组键值对
# salaries = {
#
#     "xiaolong3":30000,
#     "xiaolong2":3000,
#     "long1":1000,
# }
#
# #按照薪资找最高者（返回key）
#
# max_salary_person = max(salaries,key=lambda name:salaries[name])  # key=lambda
#
# print(max_salary_person)


#filter  过滤

# evens = list(filter(lambda x:x % 2 ==0,[1,2,3,4,5]))
# print(evens)
#
#
# # map：映射
# doubled = list(map(lambda  x: x*2,[1,2,3]))
# print(doubled)



# 递归函数
#
# def sum_to_n(n):
#     if n == _____:      # (1) 填写终止条件  1
#         return _____    # (2) 填写返回值   1
#     return _____ + sum_to_n(_____)  # (3)(4) 填写递推表达式  n   n-1

# names = ['Alice', 'bob', 'Charlie', 'david']
#
# result = sorted(   #排序
#     filter(  # 过滤
#         lambda x: len(x)  ==5,   #递归，给定值
#         map(lambda name:name.lower(),names)
#     )
# )
# print(result)


"""
闭包函数
什么是闭包
闭包 = 内部函数 + 外部变量 + 外部函数返回内部函数
闭：内部函数
包：内部函数被外部所引用（包裹了外部的变量）

闭包的三要素：
1.存在一个内部函数
2. 内部函数引用了外部函数的变量
3.外部函数返回了内部函数
"""


# def outer(x,y):   # 第一层的函数，存在两个值
#     def inner():    # 第二层函数
#         print(x + y)   # 引用了外部的变量   X  Y
#     return inner
#
# #创建闭包，传入参数给到外部函数中，外部函数调用内部函数中的函数体的功能进行相加
# func = outer(3,2)   # 传递参数给到外部函数中（outer）
# func()   # 得出结果



# 普通的函数进行传参
#
# def add(a,b):
#     return  a+b
# print(add(2,3))
# print(add(2,3))


# def mae_adder(x,y):
#     def adder():
#         return x+y
#
#     return adder
# adder1 = mae_adder(3,2)
#
# print(adder1())
# print(adder1())
#
#

# 装饰器
"""
装饰器： 一个特殊的闭包函数，用于给其他函数添加功能而不修改其源码

"""

# # 手动实现装饰器
#
# def run(name):   #   输入了一个 name   破坏了调用的方式
#     print('跑步')
#
# # 装饰器函数
# def decorate(func):    # 定义装饰器，接收原来的函数
#     """
#     decorate：装饰器函数：增强另一个函数的功能
#     参数func 被装饰的原始函数
#     返回的值是一个新的函数 new_func 在调用的时候添加了额外的行为
#     """
#     def new_func(name):  # 定义了一个包装的函数，并且强制要求调用者传name
#         """
#         包装后的新的函数，替换了原本的func,它要求调用者必须传递参数name
#         :param name:
#         :return:
#         """
#         print('==========')
#         print(f'我是{name}')
#         # print('我是龙仔')
#         print('==========')
#         func(name)  # 调用原函数,并且进行传参
#     return new_func   # 返回调用之后的函数
#
# # 手动装饰
# run1 = decorate(run)
# run1('龙仔')


"""
1.定义了一个 run的 函数
python读到  run(name)函数的时候
在内存地址中创建了函数对象  （不输出）记住了它

2.定义了一个函数 decorate 当python读取到这个时候  创建了一个 函数对象  decorate
    其中的 new_func 函数 也定义完了，但是没有给任何的功能
    
3.执行
run1 = decorate(run)  
调用 decorate（run）
把run对象当 参数传递给 decorate 

这个时候，func = run (在的是外部函数decorate 中)

执行decorate 的函数体 
定义内部函数 new_func(name)
然后执行 return new_func 函数对象 它记住了挖补函数的  func = run
赋值给  run1  在 new_func 闭包中，绑定了 func= run

4. 调用   run1 = 龙仔
run1 = new_func 所以相当于  new_func（’龙仔‘）

5.执行 new_func 里面的内容

6.主席那个这个龙仔之后

进入到 def run(name): 执行跑步

"""



# def universal_decorator(func):
#     def wrapper(*args, **kwargs):
#         print("【装饰器：开始】")
#         result = func(*args, **kwargs)  # 调用原函数
#         print("【装饰器：结束】")
#         return result
#     return wrapper
#
# def greet(name):
#     print(f"Hello, {name}!")
#
# # 手动装饰
# greet = universal_decorator(greet)
# greet("Alice")

"""
装饰器：在不修改原函数的前提下，增加他的功能
接收一个函数作为参数
返回一个新的函数（包装后的）
再不修改与那函数的前期下，增强它的功能
"""





# def universal_decorator(func):    #  是一个装饰器，输入一个参数
#     def wrapper(*args,**kwargs):   # 内层函数，用来包装原函数，主要是通过 *args,**kwargs 来接收任意参数
#         print('装饰器开始')    #行为
#         result = func(*args,**kwargs)   # 调用原函数
#         print('装饰器结束')   # 行为
#         return result   # 返回原函数的结果，不改变行为
#     return wrapper     # 返回包装后的函数
#
#
# def greet(name):
#     print(f"Hello, {name}!")
#
# greet  = universal_decorator(greet)    # 把 greet 函数传递给 universal_decorator 再进行赋值给 greet
# greet('Allen')   # 传入参数




"""
简化装饰器: @   语法糖

@ 装饰器的函数名称
def 被装饰的函数（）：
被装饰的函数 = 装饰器函数名称（被装饰的函数）
"""




# 时间装饰器

# from _datetime  import   datetime
#
#
# def run_time(func):
#     def new_func(n):
#         start = datetime.now()    #记录开始的时间
#         print(f"开始的时间{start}")
#         func(n)
#         end = datetime.now()
#         print(f"结束的时间{end}")
#         print(f"花费的时间{end - start}")
#     return  new_func   # 返回包装后的函数
#
#
# @run_time
# def for1(n):
#     total =0
#     for i in range(1,n+1):
#         total +=i
#         print(f"1到 {n}的和：{total}")
# for1(100000)




# 支持任意参数的时间装饰器

# from datetime import datetime
#
# def timer(func):
#     def wrapper(*args,**kwargs):
#         start = datetime.now()
#         result = func(*args,**kwargs)
#         end = datetime.now()
#
#         print(f"{func.__name__}耗时：{end - start}")   # func.__name__ 记录调用的函数名称
#
#         return result
#     return wrapper
#
# @timer
# def shopping(items):
#
#     for item in items:
#         pass
#     print("购物完成")
#
# shopping(['牛奶，‘面包'])
#



from datetime import datetime
import functools
@functools.lru_cache(maxsize=128)
def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n - 1)
def log_and_time(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"【调用】{func.__name__}({args}, {kwargs})")
        start = datetime.now()
        result = func(*args, **kwargs)
        end = datetime.now()
        print(f"【返回】{result} | 耗时: {end - start}")
        return result
    return wrapper
def make_multiplier(factor):
    def multiplier(x):
        return x * factor
    return multiplier
data = [
    {'name': 'A', 'value': 10},
    {'name': 'B', 'value': 5},
    {'name': 'C', 'value': 15},
]
if __name__ == "__main__":
    safe_factorial = log_and_time(factorial)
    print("5! =", safe_factorial(5))
    double = make_multiplier(2)
    triple = make_multiplier(3)
    print("double(4) =", double(4))    # 8
    print("triple(4) =", triple(4))    # 12
    sorted_data = sorted(data, key=lambda d: d['value'], reverse=True)
    print("按 value 降序:", [d['name'] for d in sorted_data])

